package com.pyl.admin.core.shiro;

import java.util.List;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import com.pyl.admin.core.constant.AdminConst;
import com.pyl.admin.core.enums.StatusEnum;
import com.pyl.admin.system.entity.SysRole;
import com.pyl.admin.system.entity.SysUser;
import com.pyl.admin.system.service.SysRoleService;
import com.pyl.admin.system.service.SysUserService;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;

/**
 * @author 灵魂贰婶
 * @date 2018/8/14
 */
public class AuthRealm extends AuthorizingRealm {

	@Autowired
	private SysUserService sysUserService;

	@Autowired
	private SysRoleService sysRoleService;

	/**
	 * 授权逻辑
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 获取用户Principal对象
		SysUser sysUser = (SysUser) principal.getPrimaryPrincipal();

		// 管理员拥有所有权限
		if (sysUser.getId().equals(AdminConst.ADMIN_ID)) {
			info.addRole(AdminConst.ADMIN_ROLE_NAME);
			info.addStringPermission("*");
			return info;
		}
		List<SysRole> sysRoles = sysRoleService.selectUserRoleList(sysUser.getId(),
				Integer.valueOf(StatusEnum.OK.getCode()));

		if (CollectionUtil.isNotEmpty(sysRoles)) {
			// 将角色和菜单封装到Subject主体对象
			sysUser.setRoles(sysRoles);
			// 赋予角色和资源授权
			sysRoles.forEach(role -> {
				info.addRole(role.getName());
				role.getSysMenus().forEach(menu -> {
					if (!menu.getUrl().equals("#")) {
						info.addStringPermission(menu.getUrl());
					}
				});
			});
			//加入框架主页
			info.addStringPermission("/main");
		}
		return info;
	}

	/**
	 * 认证逻辑
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
			throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
		// 获取数据库中的用户名密码
		SysUser sysUser = sysUserService.selectOneByUserName(token.getUsername());
		// 判断用户名是否存在
		if (ObjectUtil.isNull(sysUser)) {
			throw new UnknownAccountException();
		}
		// 该用户被冻结
		if (Integer.valueOf(StatusEnum.FREEZED.getCode()).equals(sysUser.getStatus())) {
			throw new LockedAccountException();
		}
		// 对盐进行加密处理
		ByteSource salt = ByteSource.Util.bytes(sysUser.getSalt());
		/**
		 * 传入密码自动判断是否正确 参数1：传入对象给Principal 参数2：正确的用户密码 参数3：加盐处理 参数4：固定写法
		 */
		return new SimpleAuthenticationInfo(sysUser, sysUser.getPassword(), salt, getName());
	}

	/**
	 * 设置认证加密方式
	 */
	@Override
	public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
		matcher.setHashAlgorithmName(ShiroUtil.hashAlgorithmName);
		matcher.setHashIterations(ShiroUtil.hashIterations);
		super.setCredentialsMatcher(matcher);
	}
}
